/**
    @file physics.hpp
    @brief Game physics
*/
#ifndef PM3_PHYSICS_HPP
#define PM3_PHYSICS_HPP

#include "logger.hpp"
#include "interface.hpp"

#include "bullet/BtOgrePG.h"
#include "bullet/BtOgreGP.h"
#include "bullet/BtOgreExtras.h"

#include "BulletCollision/CollisionDispatch/btInternalEdgeUtility.h"

namespace pm3 {
    /**
        @class PHYSICS
        @brief Game physics class
    */
    class PHYSICS: public Ogre::Singleton<PHYSICS> {
    friend class GAME;
    public:
            /**
                @brief Constructor
            */
            PHYSICS();
            /**
                @brief Destructor
            */
            ~PHYSICS();

            /**
                @brief Returns a pointer to world physics
                @return Pointer to world physics node
            */
            inline btDynamicsWorld *get_physics_world() const {
                return m_physics_world;
            }

            /**
                @brief Returns a pointer to physics debug drawer
                @return Pointer to physics debug drawer
            */
            inline BtOgre::DebugDrawer *get_physics_debug() const {
                return m_physics_debug;
            }

            /**
                @brief Sets up physics laws
            */
            void init();

        protected:
            //! Pointer to physics broadphase check range
            btAxisSweep3 *m_broadphase;
            //! Pointer to collision detection configuration
            btDefaultCollisionConfiguration *m_collision_cfg;
            //! Pointer to collision dispatcher
            btCollisionDispatcher *m_dispatcher;
            //! Pointer to physics solver
            btSequentialImpulseConstraintSolver *m_solver;

            //! Pointer to world physics
            btDynamicsWorld *m_physics_world;
            //! Pointer to physics debug drawer
            BtOgre::DebugDrawer *m_physics_debug;
    };

    //! Physics global
    extern PHYSICS g_physics;

    //! Contact added callback global
    extern ContactAddedCallback g_contact_added_callback;

    static bool contact_added_callback( 
        btManifoldPoint& cp, const btCollisionObject* colObj0, 
        int partId0, int index0, const btCollisionObject* colObj1, int partId1, int index1 );
}

#endif

